package net.takela.auth.login.filter;

import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import net.takela.auth.login.AuthContext;
import net.takela.common.spring.exception.AuthException;
import net.takela.common.spring.exception.StatusCodeException;
import net.takela.common.web.model.AuthUser;
import net.takela.auth.token.token.AuthTokenManager;
import net.takela.auth.token.token.AuthTokenPayload;
import net.takela.auth.token.token.AuthTokenProperties;
import org.springframework.util.AntPathMatcher;

import java.io.IOException;

public class AuthTokenFilter implements Filter {
    private final AuthTokenProperties authTokenProperties;
    private final AuthTokenManager authTokenManager;

    private Class<? extends AuthUser>  userClass = AuthUser.class;
    public Class<? extends AuthUser> getUserClass() {
        return userClass;
    }

    public void setUserClass(Class<? extends AuthUser> userClass) {
        this.userClass = userClass;
    }

    private final AntPathMatcher antPathMatcher = new AntPathMatcher();
    public AuthTokenFilter(AuthTokenProperties authTokenProperties, AuthTokenManager authTokenManager) {
        this.authTokenProperties = authTokenProperties;
        this.authTokenManager = authTokenManager;
    }

    /**
     * 策略：
     * 如果存在匿名url名单，并且匹配上则放行
     * 如果不在checkUrl，则默认全部校验
     * @param servletRequest
     * @param servletResponse
     * @param filterChain
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        //先检查当前用户是否登录
        AuthUser user = null;
        try{
            AuthTokenPayload<?> p = authTokenManager.parseUserInfoFromRequest(httpServletRequest, userClass);
            user = (AuthUser)p.getUserInfo();
            httpServletRequest.setAttribute(AuthContext.USER_KEY, user);
        }catch (Exception ignored){
        }

        boolean isAnonymous = authTokenProperties.getAnonymousUrls().stream().anyMatch( url -> antPathMatcher.match(url, httpServletRequest.getRequestURI()) );
        //在匿名名单里
        if (isAnonymous){
            filterChain.doFilter(servletRequest, servletResponse);
            return;
        }
        //存在checkUrls,但是不匹配就不验证
        if (authTokenProperties.getCheckUrls() != null && !authTokenProperties.getCheckUrls().isEmpty()) {
            boolean needCheck = authTokenProperties.getCheckUrls().stream().anyMatch(url -> antPathMatcher.match(url, httpServletRequest.getRequestURI()));
            if (!needCheck){
                filterChain.doFilter(servletRequest, servletResponse);
                return;
            }
        }
        //如果没有登录则抛出异常
        if ( user == null ){
            AuthException authException = new AuthException();
            httpServletRequest.setAttribute(StatusCodeException.COMMON_EXCEPTION_REQ_KEY, authException);
            throw authException;
        }
        filterChain.doFilter(servletRequest, servletResponse);
    }
}
